package com.hyt.it.ogt.ks.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.common.apiInfor.DataType;
import com.hyt.common.apiInfor.ParamType;
import com.hyt.core.exception.NestedBusinessException;
import com.hyt.core.util.FastJsonUtil;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.ks.base.BaseController;
import com.hyt.it.ogt.ks.config.ConfigManager;
import com.hyt.it.ogt.ks.config.KsBizRunTimeException;
import com.hyt.it.ogt.ks.enums.*;
import com.hyt.it.ogt.ks.feign.KwClient;
import com.hyt.it.ogt.ks.model.dto.VerifyAnswerOptionsDTO;
import com.hyt.it.ogt.ks.model.entity.*;
import com.hyt.it.ogt.ks.model.entity.mongodb.CandidateAnswerLogBackup;
import com.hyt.it.ogt.ks.model.vo.*;
import com.hyt.it.ogt.ks.model.xyvo.ExamCustomizationVO;
import com.hyt.it.ogt.ks.service.Event.CandidateAnswerLogEvent;
import com.hyt.it.ogt.ks.service.*;
import com.hyt.it.ogt.ks.util.KeyDefineCommon;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  答题页面接口
 * </p>
 *
 * @author caihaiyan
 * @since 2020-06-11
 * 修正上个提交
 */

@RestController
@RequestMapping("/ks/exam-paper")
@Api(tags = "1.试卷及作答接口", value = "试卷及作答接口")
@ApiSort(1)
@Slf4j
public class ExamPaperController extends BaseController {
    @Resource
    private ConfigManager configManager;
	@Resource
	private ICandidateProcessService iCandidateProcessService;
	@Resource
	private ICandidateAnswerService iCandidateAnswerService;
	@Resource
    private KwClient kwClient;
	@Resource
    private RedisTemplate redisTemplate;
    @Resource
    private IExamCacheService iExamCacheService;
    @Resource
    private ICandidatePaperService iCandidatePaperService;
    @Resource
    private IThirdInterfaceService iThirdInterfaceService;
    @Resource
    private ICandidateLogService iCandidateLogService;
    @Resource
    private IPaperInitService iPaperInitService;
    @Resource
    private ICollectLogService iCollectLogService;
    @Resource
    private IScoreService iScoreService;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Resource
    private ILogService iLogService;

	@ApiOperation(value = "1.1.1 获取小题号列表", notes = "状态码：20000:成功，42010106：获取失败，42010103：异常")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING,
                paramType = ParamType.QUERY, required = true),
		@ApiImplicitParam(name = "candidateId", value = "考生准考号", dataType = DataType.STRING,
                paramType = ParamType.QUERY, required = true)
	})
	@ApiOperationSort(1)
    @GetMapping("getTopic")
    public ApiResponse<ExamPaperTopicVO> getTopic(String examId, String candidateId, HttpServletRequest request){
        iCandidateLogService.printlnLog("getTopic接口请求参数", examId, candidateId);
        try {
            // 增加考试时间是否已经开始判断
            String json = kwClient.checkExamStartTime(examId);
            ApiResponse response = JSON.parseObject(json, ApiResponse.class);
            if(response.getData() != null && !Boolean.valueOf(response.getData().toString()).booleanValue()) {
                return ApiResponse.<ExamPaperTopicVO>builder().code(BizStatusCode.EXAM_NOT_START.getCode()).build();
            }
            ExamPaperTopicVO vo = iCandidateProcessService.getTopic(examId, candidateId, request);
            return ApiResponse.<ExamPaperTopicVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode()).data(vo).build();
        } catch (KsBizRunTimeException e) {
            return ApiResponse.<ExamPaperTopicVO>builder().code(e.getCode()).build();
        } catch (NestedBusinessException e) {
            log.error(StringUtils.join(BizStatusCode.GET_PAPER_ERROR.getCode(), ": "), e);
            return ApiResponse.<ExamPaperTopicVO>builder().code(BizStatusCode.GET_PAPER_ERROR.getCode()).build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.GET_QUESTION_FAIL.getCode(), ": "), e);
            return ApiResponse.<ExamPaperTopicVO>builder().code(BizStatusCode.GET_QUESTION_FAIL.getCode()).build();
        }
    }

    @ApiOperation(value = "1.1.7 初始化考生试卷信息", notes = "20000:成功，42010107：初始化失败，42010107：异常")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING,
                    paramType = ParamType.QUERY, required = true),
            @ApiImplicitParam(name = "candidateId", value = "考生ID", dataType = DataType.STRING,
                    paramType = ParamType.QUERY, required = true)
    })
    @ApiOperationSort(7)
    @GetMapping("initPaper")
    public ApiResponse<InitPaperVO> initPaper(String examId, String candidateId){
        String key = KeyDefineCommon.getCandidateInitData(examId, candidateId);
        try {
            // 防止考生连续多次点击进入考试，只允许一个请求初始化，其他请求等待，如果为空就set值，并返回1(true),反之返回false
            Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "true",
                    configManager.getCandidateDataInitTime(), TimeUnit.SECONDS);
            if (flag) {
                return ApiResponse.<InitPaperVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode())
                        .data(iPaperInitService.initPaper(examId, candidateId)).build();
            } else {
                return ApiResponse.<InitPaperVO>builder().code(BizStatusCode.DOING_INIT_PAPER.getCode()).build();
            }
        } catch (KsBizRunTimeException e) {
            log.error("初始化考生试卷信息不符合条件: ", e);
            if (e.getCode() == BizStatusCode.GET_CADIDATE_PAPER_NONE.getCode().intValue()) {
                // 试卷没有导入
            	return ApiResponse.<InitPaperVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode())
                        .data(InitPaperVO.builder().websocket(configManager.getWebsocketUrl())
                                .paperNone(true).build()).build();
            }
            return ApiResponse.<InitPaperVO>builder().code(e.getCode()).build();
        } catch (Exception e) {
            log.error("initPaper接口异常: ", e);
            return ApiResponse.<InitPaperVO>builder().code(BizStatusCode.INIT_PAPER_ERROR.getCode()).build();
        } finally {
            redisTemplate.delete(key);
        }
    }

	@ApiOperation(value = "1.1.2  获取一个题目", notes = "答题页主区域：通过题目ID获取一个小题的题目（包括大题说明）" +
            "，状态码：20000:成功，41010102：异常")
	    @ApiImplicitParams({@ApiImplicitParam(name = "itemId", value = "小题id", dataType = DataType.STRING,
            paramType = ParamType.QUERY, required = true),
		@ApiImplicitParam(name = "candidateId", value = "考生id", dataType = DataType.STRING,
            paramType = ParamType.QUERY, required = true),
		@ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING,
            paramType = ParamType.QUERY, required = true),
        @ApiImplicitParam(name = "paperSort", value = "试卷顺序号", dataType = DataType.STRING,
            paramType = ParamType.QUERY, required = true),
        @ApiImplicitParam(name = "language", value = "语种(简体中文（cn）、cht（繁体中文）、en（英语）、pot（葡萄牙语）)",
                dataType = DataType.STRING, paramType = ParamType.QUERY, required = true),
        @ApiImplicitParam(name = "childItemSort", value = "子小题排序号", dataType = DataType.INT,
                paramType = ParamType.QUERY, required = false),
    })
	@ApiOperationSort(2)
    @GetMapping("question")
    public ApiResponse<PaperBigQuestionVO> getQuestion(@RequestParam String itemId, @RequestParam String candidateId,
                                                       @RequestParam String examId,
                                                       @RequestParam(required = false) Integer paperSort,
                                                       @RequestParam(required = false) String language,
                                                       @RequestParam(required = false) Integer childItemSort,
                                                       HttpServletRequest request) {
        iCandidateLogService.printlnLog("getQuestion接口请求参数", examId, candidateId, itemId, String.valueOf(paperSort), String.valueOf(childItemSort));
        try {
            if (StringUtils.isBlank(language)) {
                language = TranslateLanguageCode.ZH.getCode();
            }
            // 定时保存答案题型
            PaperBigQuestionVO data = iCandidateProcessService.getQuestion(itemId, candidateId, examId, paperSort, language, childItemSort, request);
            if (PaperItemTypeCode.ITEM_TYPE_COMPOUND_CODE.getCode().equalsIgnoreCase(data.getItemData().getItemType())
                    || PaperItemTypeCode.ITEM_TYPE_CASE_ANALYSIS_CODE.getCode().equalsIgnoreCase(data.getItemData().getItemType())
                    || PaperItemTypeCode.ITEM_TYPE_SHORT_ANSWER_CODE.getCode().equalsIgnoreCase(data.getItemData().getItemType())
                    || PaperItemTypeCode.ITEM_TYPE_CLOZE_FILL_IN_BLANKS_CODE.getCode().equalsIgnoreCase(data.getItemData().getItemType())
                    || PaperItemTypeCode.ITEM_TYPE_MATCHING_CODE.getCode().equalsIgnoreCase(data.getItemData().getItemType())
                    || data.getItemData().getParentSort() != null) {
                data.setSaveInterval(configManager.getSaveAnswerInterval());
            }

            if(Objects.nonNull(data) && Objects.nonNull(data.getItemData())
                    && Objects.equals(data.getItemData().getOpenItemTiming(),Boolean.TRUE)) {
                data.setSaveOutTimeSecond(configManager.getSaveOutTimeSecond());
            }


            /*
            if(data.getItemData().getOpenItemTiming()) {
                data.setSaveOutTimeSecond(configManager.getSaveOutTimeSecond());
            }*/


            String uuid = UUIDUtils.randomUUID();
            data.setUuid(uuid);
            redisTemplate.opsForValue().set(KeyDefineCommon.getPictureItemUploadKey(examId, candidateId), uuid, 1, TimeUnit.DAYS);
            return ApiResponse.<PaperBigQuestionVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode()).data(data).build();
        } catch (Exception e) {
            log.error("{}：{}", BizStatusCode.GET_SMALL_QUESTION_FAIL.getCode(), e);
            return ApiResponse.<PaperBigQuestionVO>builder().code(BizStatusCode.GET_SMALL_QUESTION_FAIL.getCode()).build();
        }
    }

	@ApiOperation(value = "1.1.3 标记题目", notes = "标记收藏一个题目，状态码：20000:成功，42010301: 更新失败,42010104：异常")
	@ApiOperationSort(3)
    @PostMapping("markQuestion")
    public ApiResponse markQuestion(@RequestBody MarkQuestionVO markQuestionVO){
        try {
        	logger.info("标记题目：{}", markQuestionVO.toString());
            CandidatePaper cp = iCandidatePaperService.lambdaQuery()
                    .select(CandidatePaper::getPaperId, CandidatePaper::getPaperVersion)
                    .eq(CandidatePaper::getExamId, markQuestionVO.getExamId())
                    .eq(CandidatePaper::getCandidateId, markQuestionVO.getCandidateId())
                    .eq(CandidatePaper::getMixSort, markQuestionVO.getPaperSort()).one();

            CandidateAnswer ca = iCandidateAnswerService.lambdaQuery().select(CandidateAnswer::getId)
                    .eq(CandidateAnswer::getExamId, markQuestionVO.getExamId())
                    .eq(CandidateAnswer::getCandidateId, markQuestionVO.getCandidateId())
                    .eq(CandidateAnswer::getPaperId, cp.getPaperId())
                    .eq(CandidateAnswer::getPaperVersion, cp.getPaperVersion())
                    .eq(CandidateAnswer::getDelFlag, false)
                    .eq(CandidateAnswer::getItemId, markQuestionVO.getItemId()).one();

            boolean success = iCandidateAnswerService.lambdaUpdate().eq(CandidateAnswer::getId, ca.getId())
                    .set(CandidateAnswer::getFlagState, markQuestionVO.getFlagState()).update();

        	if(!success){
                return ApiResponse.builder()
                        .code(BizStatusCode.MARK_QUESTION_FAIL.getCode())
                        .build();
            }
            if(markQuestionVO.getFlagState() == 2) {
                iLogService.markItem(markQuestionVO.getExamId(), markQuestionVO.getCandidateId(), markQuestionVO.getItemId());
            }
            return ApiResponse.builder()
                    .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                    .build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.TAG_QUESTION_CODE_FAIL.getCode(), ": "), e);
            return ApiResponse.builder()
                    .code(BizStatusCode.TAG_QUESTION_CODE_FAIL.getCode())
                    .build();
        }
    }

	@ApiOperation(value = "1.1.5 保存答案", notes = "保存考生的作答，状态码：20000:成功，42010105：保存失败，42010502：异常，42010503：该考试项目已停用")
	@ApiOperationSort(5)
    @PostMapping("saveQuestion")
    public ApiResponse<PaperTopicItemListVO> saveQuestion(@RequestBody @Valid CandidateQusAnsVO answer, BindingResult bindingResult, HttpServletRequest request){
        long s1 = System.currentTimeMillis();
	    try{
            CandidateAnswerLogBackup logBackup = CandidateAnswerLogBackup.builder().examId(answer.getExamId()).candidateId(answer.getCandidateId())
                    .paperSort(answer.getPaperSort()).createDate(LocalDateTime.now()).requestJson(JSON.toJSONString(answer)).build();
            applicationEventPublisher.publishEvent(new CandidateAnswerLogEvent(logBackup,answer));
            s1 = System.currentTimeMillis() - s1;
        } catch (Exception e) {
            log.error("保存答案失败saveQuestion:{}", e.getMessage());
        }
        long s2 = System.currentTimeMillis();
        try {
            //先处理必传参数是否有缺失
            if (bindingResult.hasErrors()) {
                log.info("考生保存答案接口参数不对:{}", bindingResult.getAllErrors());
                return ApiResponse.<PaperTopicItemListVO>builder()
                        .code(BizStatusCode.ANSWER_EXAMID_EXISTS.getCode()).build();
            }
            VerifyAnswerOptionsDTO verify = iCandidateAnswerService.verifyAnswerOptions(answer);
            //检测项目是否已停用
            if(!verify.getIsExamPushed()) {
                return ApiResponse.<PaperTopicItemListVO>builder()
                        .code(BizStatusCode.SAVE_QUESTION_FAIL_PUBLISH.getCode()).build();
            }
            //是否发布
            if(verify.getIsFinishExamOrOverEndTime()){
                //之前的业务逻辑是直接返回null的
                return ApiResponse.<PaperTopicItemListVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode()).data(null).build();
            }
            //itemType  --> UserAnswer是否匹配
            if(!verify.getIsItemTypeMatch()){
                log.error("上传的考生答案与题目型不符合，上传的参数为:【{}】",answer);
                iCandidateAnswerService.insertSaveQuestionLog(answer);
                return ApiResponse.<PaperTopicItemListVO>builder()
                        .code(BizStatusCode.ANSWER_TYPE_USERANSWER_NOT_MATCH.getCode()).build();
            }
            s2 = System.currentTimeMillis() - s2;
            long s3 = System.currentTimeMillis();
            PaperTopicItemListVO list = iCandidateAnswerService.saveQuestion(answer,verify, request);
            String timeMillis = "\n-----------------------------------------\n" +
                    "耗时    任务名称\n" +
                    s1 + "ms    " + "发布答案备份日志事件\n" +
                    s2 + "ms    " + "构建答案验证实体\n" +
                    (System.currentTimeMillis() - s3) + "ms    " + "保存答案\n" +
                    "-----------------------------------------\n";
            log.info(timeMillis);
            return ApiResponse.<PaperTopicItemListVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode()).data(list).build();
        }catch (KsBizRunTimeException e){
            return ApiResponse.<PaperTopicItemListVO>builder().code(e.getCode()).build();
        }catch (NestedBusinessException e){
            return ApiResponse.<PaperTopicItemListVO>builder().code(BizStatusCode.SAVE_QUESTION_FAIL.getCode()).build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.SAVE_EXAM_ANSWER.getCode(), ": "), e);
            return ApiResponse.<PaperTopicItemListVO>builder().code(BizStatusCode.SAVE_EXAM_ANSWER.getCode()).build();
        }
    }

    @ApiOperation(value = "1.1.6 考生交卷接口", notes = "状态码：20000:成功，42010603：参数校验不通过，42010603：异常，42010604：该考试项目已停用")
    @ApiOperationSort(6)
    @PutMapping("finishExam")
    public ApiResponse<FinishVO> finishExam(@RequestBody @Valid CandidateFinishExamVO param, BindingResult bindingResult, HttpServletRequest request){
        String paramString = FastJsonUtil.getBeanToJson(param);
        log.info("## finishExam接口请求参数：{}、{}", paramString, request);
        String key = KeyDefineCommon.getFinishExamRepeatSubmitKey(param.getExamId(), param.getCandidateId());
        // 如果为空就set值，并返回1(true), 如果存在(不为空)不进行操作，并返回0(false)）
        Boolean isRepeatSubmit = redisTemplate.opsForValue().setIfAbsent(key, "true", 2, TimeUnit.MINUTES);
        // 没有获取到锁说明两分钟内二次交卷，就直接阻断返回了
        if(!isRepeatSubmit){
            return ApiResponse.<FinishVO>builder().code(BizStatusCode.REPEAT_SUBMIT_FINISH_EXAM.getCode()).build();
        }
        try {
            // 校验交卷条件
            ApiResponse<FinishVO> validateResult = validateCandidateFinishExam(param, bindingResult, key);
            if(null != validateResult) {
                return validateResult;
            }

            // 获取考生考试过程记录
            CandidateProcess candidateProcess = iCandidateProcessService.getCandidateProcessByExamIdAndCandidateId(param.getExamId(), param.getCandidateId());

            if (candidateProcess.getExamStatus().intValue() >= CandidateStatusCode.COMMIT.getCode().intValue()) {
                // 如果是管理端强制收卷
                if(FinishExamType.FORCE.getCode().equals(param.getFinishType())) {
                    iScoreService.calcScoreByCandidate(param.getExamId(), param.getCandidateId(), null, false);
                }
                return ApiResponse.<FinishVO>builder()
                        .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                        .data(FinishVO.builder()
                                .finishExam(true)
                                .hasRemainTime(false)
                                .build())
                        .build();
            }
            // 如果是自动交卷，检测是否还有剩余时长
            if (param.getFinishType().intValue() == 4) {
                // 获取考生剩余时长
                CandidateTimeLength candidateTimeLength = iCandidatePaperService.getTimeLength(param.getExamId(), param.getCandidateId(), param.getPaperSort());

                if((candidateTimeLength.getRemainingTime() + candidateTimeLength.getExtraTime()) >= 60000) {
                    return ApiResponse.<FinishVO>builder()
                            .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                            .data(FinishVO.builder()
                                    .finishExam(false)
                                    .hasRemainTime(true)
                                    .remainingTime(candidateTimeLength.getRemainingTime() +
                                            candidateTimeLength.getExtraTime())
                                    .build())
                            .build();
                }
            }

            FinishVO finishVO = iCandidateAnswerService.finishExam(param, request);
            // 交卷后处理事宜
            if(finishVO.getFinishExam()){
                try {

                    // 异步调用
                    iThirdInterfaceService.finishExamCallback(param.getExamId(), param.getCandidateId());
                } catch (Exception e) {
                    log.error("交卷后调用第三方接口异常：", e);
                    e.printStackTrace();
                }
                // 判断是否定制考试（编程题）
                String json = kwClient.getExamCustomizationIsContainCodingPaper(param.getExamId());
                ApiResponse<Boolean> apiResponse = ApiResponse.ConvertRet(json, Boolean.class);
                if(apiResponse.getData() && candidateProcess.getOtherScore() == null) {
                    finishVO.setPaperType(3);
                    finishVO.setFinishExam(false);
                    iCandidateProcessService.change2Testing(param.getExamId(), param.getCandidateId());
                }
            }
            iCandidateLogService.printlnLog("finishExam接口返回数据", param.getExamId(),
                    param.getCandidateId(), JSON.toJSONString(finishVO));
            /*
            if (param.getFinishAllPaper() || finishVO.getFinishExam()) {
                String token = (String) request.getAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE);
                iCandidateProcessService.revokeToken(token);
            }
             */
            return ApiResponse.<FinishVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode()).data(finishVO).build();
        }catch (KsBizRunTimeException e){
            log.error("## finishExam接口异常:{}", paramString, e);
            return ApiResponse.<FinishVO>builder().code(e.getCode()).build();
        } catch (Exception e) {
            log.error("## finishExam接口异常:{}", paramString, e);
            iCollectLogService.save(CollectLog.builder().candidateId(param.getCandidateId()).examId(param.getExamId())
                    .errorType(ErrorTypeCode.ERROR_FINISH_EXAM.getCode()).errMsg(paramString).build());
            return ApiResponse.<FinishVO>builder().code(BizStatusCode.CANDIDATE_COMMIT_PAPER_ERROR.getCode()).build();
        } finally {
            redisTemplate.delete(key);
        }
    }

	public ApiResponse<FinishVO> validateCandidateFinishExam(CandidateFinishExamVO param, BindingResult bindingResult, String key) {
		if (bindingResult.hasErrors()) {
			log.info("考生交卷接口参数不对:{}", bindingResult.getAllErrors());
			return ApiResponse.<FinishVO> builder().code(BizStatusCode.CANDIDATE_COMMIT_PAPER_PARAM_VALID.getCode()).build();
		}
		// 检测项目是否已停用
		if (!iExamCacheService.getPublishExam(param.getExamId())) {
			return ApiResponse.<FinishVO> builder().code(BizStatusCode.CANDIDATE_COMMIT_PAPER_ERROR_PUBLISH.getCode()).build();
		}
		return null;
	}

    @ApiOperation(value = "1.1.9 获取标答和描述", notes = "练习模式中查看小题标答和解析，状态码：20000:成功，41010102：异常")
    @ApiImplicitParams({@ApiImplicitParam(name = "itemId", value = "小题id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
            ,@ApiImplicitParam(name = "candidateId", value = "考生id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
            ,@ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
            ,@ApiImplicitParam(name = "sort", value = "试卷顺序号", dataType = DataType.STRING, paramType = ParamType.QUERY,
            required = true)})
    @ApiOperationSort(9)
    @GetMapping("getQuestionStandardAnswerAndDescription")
    public ApiResponse<PaperBigQuestionVO> getQuestionStandardAnswerAndDescription(@RequestParam String itemId,
                                                                                    @RequestParam String candidateId,
                                                                                    @RequestParam String examId,
                                                                                   @RequestParam Integer paperSort,
                                                                                   @RequestParam(required = false) Integer childItemSort,
                                                                                   HttpServletRequest request){
        try {
            //大题
            PaperBigQuestionVO paperTopicVO = iCandidateProcessService.getQuestion(itemId, candidateId, examId, paperSort, TranslateLanguageCode.ZH.getCode(), childItemSort,request);
            return ApiResponse.<PaperBigQuestionVO>builder()
                    .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                    .data(paperTopicVO)
                    .build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.GET_SMALL_QUESTION_FAIL.getCode(), ": "), e);
            return ApiResponse.<PaperBigQuestionVO>builder()
                    .code(BizStatusCode.GET_SMALL_QUESTION_FAIL.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "1.1.10 性格测试卷-查询分页下所有小题", notes = "状态码：20000:成功，18003：异常")
    @ApiImplicitParams({@ApiImplicitParam(name = "candidateId", value = "考生id", dataType = DataType.STRING,
            paramType = ParamType.QUERY, required = true)
            ,@ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING,
            paramType = ParamType.QUERY, required = true)
            ,@ApiImplicitParam(name = "current", value = "当前页", dataType = DataType.INT,
            paramType = ParamType.QUERY, required = true)
            ,@ApiImplicitParam(name = "paperSort", value = "试卷顺序号", dataType = DataType.INT,
            paramType = ParamType.QUERY, required = true)})
    @ApiOperationSort(10)
    @GetMapping("getQuestionList")
    public ApiResponse<PaperTopicItemListVO> getQuestionList(@RequestParam String candidateId,
                                                             @RequestParam String examId, @RequestParam Integer current,
                                                             @RequestParam Integer paperSort){
        iCandidateLogService.printlnLog("getQuestionList接口请求参数", examId, candidateId, current.toString(),
                paperSort.toString());
        try {
            PaperTopicItemListVO itemList = iCandidateProcessService.getQuestionListByTopicId(candidateId, examId,
                    current, paperSort);
            iCandidateLogService.printlnLog("getQuestionList接口返回数据", examId, candidateId, current.toString(),
                    paperSort.toString(), itemList != null ? String.valueOf(itemList.getItemData().size()) : "");
            return ApiResponse.<PaperTopicItemListVO>builder().code(BizStatusCode.KS_SUCCESS_OK.getCode()).data(itemList).build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.GET_SMALL_QUESTION_FAIL.getCode(), ": "), e);
            return ApiResponse.<PaperTopicItemListVO>builder().code(BizStatusCode.GET_SMALL_QUESTION_FAIL.getCode()).build();
        }
    }
    
    @ApiOperation(value = "1.1.11 获取面试地址", notes = "获取面试地址，状态码：20000:成功，42011101：异常", response = InterviewUrlVO.class)
    @ApiImplicitParams({
    	@ApiImplicitParam(name = "candidateId", value = "考生id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    	,@ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    })
    @ApiOperationSort(11)
    @GetMapping("getInterviewUrl")
    public Object getInterviewUrl(@RequestParam String candidateId, @RequestParam String examId){
        try {
        	InterviewUrlVO interviewUrl = new InterviewUrlVO();
        	if (!configManager.getInterviewexamIds().contains(examId)) {
        		return ApiResponse.builder()
                        .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                        .data(interviewUrl)
                        .build();
        	}
        	String url = iCandidateAnswerService.getInterviewUrl(examId, candidateId, "interview", configManager.getInterviewModeId());
        	if(StringUtils.isNotBlank(url)) {
        		interviewUrl.setInterviewUrl(url);
        		return ApiResponse.builder()
                    .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                    .data(interviewUrl)
                    .build();
        	}
        	return ApiResponse.builder()
                    .code(BizStatusCode.GET_INTERVIEW_URL_ERROR.getCode())
                    .build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.GET_INTERVIEW_URL_ERROR.getCode(), ": "), e);
            return ApiResponse.builder()
                    .code(BizStatusCode.GET_INTERVIEW_URL_ERROR.getCode())
                    .build();
        }
    }
    
    @ApiOperation(value = "1.1.12 获取编程题地址", notes = "获取面试地址，状态码：20000:成功，42011101：异常", response = InterviewUrlVO.class)
    @ApiImplicitParams({
    	@ApiImplicitParam(name = "candidateId", value = "考生id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    	,@ApiImplicitParam(name = "examId", value = "考试项目id", dataType = DataType.STRING, paramType = ParamType.QUERY, required = true)
    })
    @ApiOperationSort(12)
    @GetMapping("getCodingQuestionUrl")
    public Object getCodingQuestionUrl(@RequestParam String candidateId, @RequestParam String examId){
        try {
        	String res = kwClient.getExamCustomization();
        	@SuppressWarnings("unchecked")
			ApiResponse<JSONArray> resResponse = JSON.parseObject(res, ApiResponse.class);
            if (resResponse.getCode().intValue() != BizStatusCode.KW_SUCCESS_OK.getCode().intValue()) {
                return res;
            }
            List<ExamCustomizationVO> examCustomizationList = JSONObject.parseArray(resResponse.getData().toString(),
        																					ExamCustomizationVO.class);
            Optional<ExamCustomizationVO> examCustomization = examCustomizationList.stream()
            		.filter(e -> "xy".equals(e.getCustomer()) && examId.equals(e.getExamId())).findFirst();
            InterviewUrlVO interviewUrl = new InterviewUrlVO();
            if (!(examCustomization.isPresent() && examCustomization.get().getCodingQuestion())) {
        		return ApiResponse.builder()
                        .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                        .data(interviewUrl)
                        .build();
        	}
            String modeId = examCustomization.get().getModeId();
        	String url = iCandidateAnswerService.getInterviewUrl(examId, candidateId, "codingQuestion", modeId);
        	if(StringUtils.isNotBlank(url)) {
        		interviewUrl.setInterviewUrl(url);
        		return ApiResponse.builder()
                    .code(BizStatusCode.KS_SUCCESS_OK.getCode())
                    .data(interviewUrl)
                    .build();
        	}
        	return ApiResponse.builder()
                    .code(BizStatusCode.GET_INTERVIEW_URL_ERROR.getCode())
                    .build();
        } catch (Exception e) {
            log.error(StringUtils.join(BizStatusCode.GET_INTERVIEW_URL_ERROR.getCode(), ": "), e);
            return ApiResponse.builder()
                    .code(BizStatusCode.GET_INTERVIEW_URL_ERROR.getCode())
                    .build();
        }
    }

    @ApiOperation(value = "1.1.13 定时保存答案", notes = "18010：异常，18335：该考试项目已停用")
    @ApiOperationSort(13)
    @PostMapping("nswer")
    public ApiResponse timingSaveAnswer(@RequestBody @Valid CandidateQusAnsVO answer,BindingResult bindingResult, HttpServletRequest request){
	    answer.setSaveType(SaveAnswerType.TIMING.getCode());
	    return this.saveQuestion(answer,bindingResult, request);
    }

    @ApiOperation(value = "1.1.14 删除初始化试卷信息")
    @ApiOperationSort(14)
    @GetMapping("clearInitPaperDataByCandidateId")
    public ApiResponse clearInitPaperDataByCandidateId(@RequestParam String candidateId){
        iCandidateProcessService.clearInitPaperDataByCandidateId(candidateId);
        return ApiResponse.builder().build();
    }

    @ApiOperation(value = "1.1.15 删除初始化试卷信息")
    @ApiOperationSort(15)
    @GetMapping("clearInitPaperDataByZkz")
    public ApiResponse clearInitPaperDataByZkz(@RequestParam Integer examCode, @RequestParam String zkz){
        iCandidateProcessService.clearInitPaperDataByCandidateId(examCode, zkz);
        return ApiResponse.builder().build();
    }
}
